contents
뮤텍스(Mutex) 와 세마포어(Semaphore) 는 둘 다 경쟁 상태(race condition)와 같은 문제를 방지하고 공유 리소스에 대한 접근을 관리하기 위해 동시성 프로그래밍에서 사용되는 동기화 기본 요소입니다. 비슷해 보이지만, 서로 다른 문제를 해결하며 결정적인 개념적 차이가 있습니다.
간단히 말해, 뮤텍스는 화장실 열쇠 하나와 같습니다. 한 번에 한 사람만 열쇠를 가질 수 있습니다. 세마포어는 똑같은 스터디룸 여러 개에 대한 열쇠 꾸러미와 같습니다. 만약 방이 5개 있다면, 5명이 열쇠를 하나씩 가져가 들어갈 수 있고, 6번째 사람은 기다려야 합니다.
뮤텍스 (상호 배제) 🔑
뮤텍스는 상호 배제(Mutual Exclusion) 의 줄임말로, 간단한 잠금(locking) 메커니즘입니다. 그 목적은 특정 코드 조각이나 공유 리소스에 한 번에 오직 하나의 스레드만 접근할 수 있도록 보장하는 것입니다. 이렇게 보호되는 코드 섹션을 임계 구역(critical section) 이라고 합니다.
핵심 개념 및 비유
1인용 공중 화장실을 상상해 보세요. 열쇠는 단 하나입니다.
- 화장실을 사용하려면 열쇠를 획득해야 합니다 (
lock). - 다른 사람이 열쇠를 가지고 있다면, 그 사람이 나올 때까지 줄을 서서 기다려야 합니다.
- 사용이 끝나면, 줄 서 있는 다음 사람이 가져갈 수 있도록 열쇠를 반납해야 합니다 (
unlock).
이 열쇠는 한 번에 한 사람만 안에 있도록 보장하여 혼란을 방지합니다.
주요 특징
- 소유권 (Ownership): 이것이 뮤텍스의 가장 중요한 특징입니다. 뮤텍스는 "소유자"라는 개념을 가집니다.
lock에 성공한 스레드가 소유자가 되며, 오직 그 스레드만이unlock할 수 있습니다. 만약 다른 스레드가unlock을 시도하면 오류가 발생합니다. - 이진 상태 (Binary State): 뮤텍스는 잠김(사용 불가) 또는 잠금 해제(사용 가능) 두 가지 상태 중 하나입니다.
- 주요 연산:
lock()(또는acquire): 잠금을 획득합니다. 만약 잠금이 이미 다른 스레드에 의해 점유되어 있다면, 현재 스레드는 잠금이 해제될 때까지 블록(대기)됩니다.unlock()(또는release): 잠금을 해제하여, 대기 중인 다른 스레드가 획득할 수 있게 합니다.
- 사용 사례: 경쟁 상태를 방지하기 위해 임계 구역을 보호할 때. 예를 들어, 여러 스레드가 증가시키는 공유 카운터 변수가 있다면, 업데이트가 원자적으로(atomically) 일어나도록 보장하기 위해 증가 연산(
counter++)을 뮤텍스 lock과 unlock으로 감쌉니다.
세마포어 🚦
세마포어는 더 일반적인 신호(signaling) 메커니즘입니다. 그 목적은 _N_개의 동일한 리소스로 구성된 풀(pool)에 대한 접근을 제어하는 것입니다. 내부 카운터를 사용하여 사용 가능한 리소스가 몇 개인지 추적합니다.
핵심 개념 및 비유
똑같은 스터디룸 5개가 있는 도서관을 상상해 보세요. 안내 데스크에는 열쇠 5개가 있습니다.
- 방을 사용하려면, 열쇠를 하나 가져갑니다 (
wait). 사용 가능한 열쇠의 수가 하나 줄어듭니다. - 만약 5개의 열쇠가 모두 사용 중이라면, 누군가 열쇠를 반납할 때까지 줄을 서서 기다려야 합니다.
- 방 사용이 끝나면, 열쇠를 반납합니다 (
signal). 사용 가능한 열쇠의 수가 하나 늘어나고, 줄의 첫 번째 사람이 이제 열쇠를 가져갈 수 있습니다.
주요 특징
- 소유권 없음 (No Ownership): 세마포어는 소유자 개념이 없습니다.
wait를 호출한 스레드가 아니더라도, 어떤 스레드든signal을 호출하여 카운터를 증가시킬 수 있습니다. 이것이 뮤텍스와의 결정적인 차이점입니다. - 카운팅 상태 (Counting State): 세마포어의 내부 카운터는 음수가 아닌 모든 정수 값을 가질 수 있습니다.
- 주요 연산:
wait()(또는acquire,P): 내부 카운터를 1 감소시킵니다. 만약 카운터가 0이면, 0보다 커질 때까지 스레드는 블록됩니다.signal()(또는release,V): 내부 카운터를 1 증가시키며, 대기 중인 스레드의 블록을 해제할 수 있습니다.
- 세마포어의 종류:
- 카운팅 세마포어: 초기 카운트가
N > 1인 정수일 수 있는 일반적인 형태입니다.N개의 리소스 풀(예: 데이터베이스 커넥션, 스레드 풀 슬롯)에 대한 접근을 제한하는 데 사용됩니다. - 이진 세마포어: 카운트가 0과 1로 제한되는 특별한 경우입니다. 뮤텍스와 동일한 상호 배제 문제를 해결하는 데 사용될 수 있지만, 소유권 제약이 없습니다.
- 카운팅 세마포어: 초기 카운트가
- 사용 사례: 한정된 리소스 풀에 접근할 수 있는 스레드의 수를 제한할 때. 예를 들어, 동시에 10개의 API 요청만 처리할 수 있는 서비스가 있다면, 10으로 초기화된 세마포어를 사용합니다.
주요 차이점 요약
| 특징 | 뮤텍스 | 세마포어 |
|---|---|---|
| 목적 | 상호 배제 (오직 하나의 스레드만 접근하도록 보장) | 동기화 (리소스 풀에 대한 접근 제어) |
| 상태 | 이진 (잠김/잠금 해제) | 정수 (음수가 아닌 카운트) |
| 소유권 | 있음. 잠근 스레드가 반드시 잠금을 해제해야 함. | 없음. 어떤 스레드든 signal을 호출하여 리소스를 해제할 수 있음. |
| 비유 | 화장실 열쇠 하나. | N개의 스터디룸에 대한 N개의 동일한 열쇠 꾸러미. |
| 메커니즘 | 잠금(Locking) 메커니즘 | 신호(Signaling) 메커니즘 |
결론적으로, 배타적인 접근을 보장하기 위해 공유 리소스를 보호해야 할 때는 뮤텍스를 사용하세요. 리소스 풀에 접근할 수 있는 스레드의 수를 제한해야 할 때는 세마포어를 사용하세요.
references